/* ************************************
 * GazeVis
 * UI
 * ************************************
 */
 
static final int INCREMENTAL = 10;
static final int TIMELINE_WIDTH = 300;

static final int TIMELINE_GAZE_X_OFFSET = 10;
static final int TIMELINE_GAZE_Y_OFFSET = 20 + VIS_HEIGHT;

static final int TIMELINE_VIS_X_OFFSET = 400;
static final int TIMELINE_VIS_Y_OFFSET = 20 + VIS_HEIGHT;


static final int STATE_PAUSED = 1;
static final int STATE_PLAYING = 2;

String formatTime( int t )
{
	int s = t / 1000;
	int minutes = s / 60;
	int seconds = s % 60;
	int milli = t % 1000;
	
	return nf(minutes, 2) + ":" + nf(seconds, 2) + "." + nf(milli, 4);	
}

PFont sliderFont = null;


// 
// class Timeline
// ________________________________________________________________________________________________________
class Timeline
{
	// data
	int curT;
	int lastT;

	// state
	int timelineState;
	
	// position
	int xOffset, yOffset;
	int sliderBeginX, sliderEndX;
	int markerPosition;
	boolean markerHold;
	
	int lowLimit, highLimit, xLowLimit, xHighLimit;
	
	Timeline(int lastTimestamp, int xOffset, int yOffset)
	{
		// create font
		if (sliderFont == null) {
			sliderFont = createFont("HelveticaBold", 11.0);
		}
		
		curT = 0;
		lastT = lastTimestamp;
		
		timelineState = STATE_PAUSED;
		this.xOffset = xOffset;
		this.yOffset = yOffset;

		// calculate slider offsets
		sliderBeginX = xOffset + 30;
		sliderEndX = xOffset + TIMELINE_WIDTH;
		markerPosition = sliderBeginX;
		markerHold = false;

		// set limits
		lowLimit = highLimit = -1;
		xLowLimit = xHighLimit = -1;		
	}
	
	int getRangeLen()
	{
		return lastT;
	}
	
	void setLimit(int _low, int _high)
	{
		lowLimit = _low;
		highLimit = _high;
		
		xLowLimit = xPos(lowLimit);
		xHighLimit = xPos(highLimit);
	}
	
	int xPos(int t)
	{
		return round(map(t, 0, lastT, sliderBeginX, sliderEndX));
	}
	
	void increment()
	{
		if (curT < lastT) {
			setCurrentT( min(lastT, curT + INCREMENTAL) );
		}
	}
	
	void decrement()
	{
		if (curT > 0) {
			setCurrentT( max(0, curT - INCREMENTAL) );
		}
	}
	
	void setCurrentT(int t)
	{
		curT = t;
		updateMarkerPosition();
	}
	
	int getCurrentT()
	{
		return curT;
	}
	
	int getState()
	{
		return timelineState;
	}
	
	void setState(int s)
	{
		timelineState  = s;
	}

	void drawTime()
	{
		int elapsed = curT;
		int remaining = lastT - elapsed;
		
		String txt = formatTime(elapsed) + "\n" + formatTime(remaining);
		
		stroke(80);
		strokeWeight(1);
		
		textFont(sliderFont);
		fill(#FFB443);
		
		rect( sliderEndX + 5, yOffset - 20, 70, 30 );
		
		fill(0);
		textAlign(LEFT, TOP);
		text( txt, sliderEndX + 5, yOffset - 20);
	}
	void render()
	{
		// draw timeline
		stroke(255);
		strokeWeight(1);
		
		line(	sliderBeginX, yOffset, 
			sliderEndX, yOffset
		);
		
		line(	sliderBeginX, yOffset - 5,
			sliderBeginX, yOffset + 5 );

		line(	sliderEndX, yOffset - 5,
			sliderEndX, yOffset + 5 );

		if (lowLimit != -1 && highLimit != -1)
		{
			fill(#FFC652, 160);
			noStroke();
			rect( xLowLimit, yOffset - 5, xHighLimit - xLowLimit, 10 );
		}
		
		// draw marker
		stroke(#FF5F5F, 200);
		
		if (markerHold)
		{
			strokeWeight(4.5);
		}
		else
		{
			strokeWeight(2.5);
		}
		
		line(	markerPosition, yOffset - 10,
			markerPosition, yOffset + 10 );
			
		// render control button (play / pause)
		switch (timelineState)
		{
		case STATE_PLAYING:
			fill(255);
			noStroke();
			
			rect( xOffset, yOffset - 5, 5, 10);
			rect( xOffset + 5 + 3, yOffset - 5, 5, 10);
			break;
		
		case STATE_PAUSED:
			fill(255);
			noStroke();
			beginShape();
			{
				vertex( xOffset, yOffset - 10 );
				vertex( xOffset, yOffset + 10 );
				vertex( xOffset + 13, yOffset ); 
			}
			endShape();
			
		}
		
		drawTime();
	}
	
	void flipState()
	{
		if (timelineState == STATE_PAUSED)
		{
			timelineState = STATE_PLAYING;
		}
		else if (timelineState == STATE_PLAYING)
		{
			timelineState = STATE_PAUSED;
		}
	}
	
	void updateMarkerPosition()
	{
		float x = map( curT, 0, lastT, sliderBeginX, sliderEndX );
		markerPosition = round(x);
	}
	
	void updateTimestamp()
	{
		float t = map(markerPosition, sliderBeginX, sliderEndX, 0, lastT);
		curT = round(t);
		if (curT < 0)
		{
			curT = 0;
		}
		else if (curT > lastT)
		{
			curT = lastT;
		}
	}
	
	boolean mousePressed()
	{
		if (mouseX >= xOffset && mouseX <= xOffset + 13) 
		{
			flipState();
			return false;
		}
		else if (mouseX >= markerPosition - 3 && mouseX <= markerPosition + 3)
		{
			markerHold = true;
			return true;
		}
		return false;
		
	}
	
	void mouseReleased()
	{
		markerHold = false;
	}
	
	void mouseDragged()
	{
		if (markerHold)
		{
			int x = mouseX;
			if (x < (lowLimit != -1 ? xLowLimit : sliderBeginX))
			{
				x =  (lowLimit != -1 ? xLowLimit : sliderBeginX);
			}
			else if (x > (highLimit != -1 ? xHighLimit : sliderEndX))
			{
				x =  (highLimit != -1 ? xHighLimit : sliderEndX);
			}
			markerPosition = x;
			updateTimestamp();
		}
	}
}

